/**
 * Copyright (c) 2008 Luciano Bustos - riaevolution.com, All Rights Reserved.
 * 
 * Contact luchyx@riaevolution.com
 * See www.riaevolution.com
 *  
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 * */
package com.riaevolution.components
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	import mx.containers.Panel;
	import mx.containers.VBox;
	import mx.controls.Button;
	import mx.core.UIComponent;
	import mx.events.CloseEvent;
	import mx.events.EffectEvent;
	import mx.events.ResizeEvent;
	
	//use namespace mx_internal;
	
	// Drag events.
	[Event(name="dragStart", type="mx.events.DragEvent")]
	[Event(name="dragComplete", type="mx.events.DragEvent")]
	
	[Event(name="onSettingsOpen", type="flash.events.Event")]
	[Event(name="onHideModalPopup", type="flash.events.Event")]
	[Event(name="onHideModalPopup", type="flash.events.Event")]
	[Event(name="onShowModalPopup", type="flash.events.Event")]
	[Event(name="onTitleBarPress", type="flash.events.Event")]
	[Event(name="onTitleBarRelease", type="flash.events.Event")]
	[Event(name="restore", type="flash.events.Event")]
	[Event(name="minimize", type="flash.events.Event")]
	[Event(name="maximizeClick", type="flash.events.Event")]
	[Event(name="maximize", type="flash.events.Event")]
	
	
	public class WindowPanel extends Panel
	{
		// Constants  panel event names
		public static const MINIMIZE:String = "minimize";
		public static const MAXIMIZE:String = "maximize";
		public static const CLOSE:String = "close";
		public static const RESTORE:String = "restore";
		
		public static const SHOW_POPUP:String = "onShowModalPopup";
		public static const HIDE_POPUP:String = "onHideModalPopup";
		
		public static const SETTINGS_OPEN_EVENT:String = "onSettingsOpen";
		public static const ON_TITLE_BAR_PRESS:String = "onTitleBarPress";
		public static const ON_TITLE_BAR_RELEASE:String = "onTitleBarRelease";
		public static const MAXIMIZE_CLICK:String = "maximizeClick";
		public static const MINIMIZE_CLICK:String = "minimizeClick";
		
		public static const MINIMIZED_HEIGHT:int = 28;

		public var originalX:Number;
		public var originalY:Number;
		public var originalWidth:Number;
		public var originalHeight:Number;
		public var originalCornerRadius:Object;
		public var autoHandleRestore:Boolean = true;
		
		
		public var inlinePopUpRender:Class = VBox;
		

		[Embed(source="icon_close.png")]
		private static var iconClose:Class;

		[Embed(source="icon_minimize.png")]
		private static var iconMinimize:Class;

		[Embed(source="icon_maximize.png")]
		private static var iconMaximize:Class;

		[Embed(source="icon_restore.png")]
		private static var iconRestore:Class;

		[Embed(source="icon_resize.gif")]
		private static var iconResize:Class;
		
		[Embed(source="icon_set.png")]
		private static var iconSettings:Class;


		protected var minimizeButton:Button;
		protected var maximizeButton:Button;
		protected var closeButton:Button;
		protected var settingsBtn:Button;
		protected var grip:UIComponent;

		protected var inSidePop:UIComponent;

		private var _modal_active:Boolean;
		private var _pop_modal:Boolean = true;
		private var _resizable:Boolean = false;
		
		public var autoBringToTop:Boolean = false;

		private var __storedAlpha:Number;
		private var __storedColor:Object;
		
		public var index:int;
		protected var destroyBool:Boolean = false;

		public function WindowPanel()
		{
			super();
			isPopUp = false;
			addEventListener(EffectEvent.EFFECT_START, feventHandler);
			addEventListener(EffectEvent.EFFECT_END, feventHandler);

		}
		/**
		* This function ensure that if the pop-up insitu is visible they must be
		* hidden if an resize effect exist. for better performance.
		*
		**/
		protected function feventHandler(event:EffectEvent):void
		{
			if(event.type == EffectEvent.EFFECT_START && modalActive && inSidePop.visible) {
				//inSidePop.visible = false;
				trace("need to implement a resize scrollbar policiy");
				//horizontalScrollPolicy="off" verticalScrollPolicy="off"
			}
			if(event.type == EffectEvent.EFFECT_END && modalActive && !inSidePop.visible) {
				//inSidePop.visible = true;
			}
		}
		public function destroy():void
		{
			destroyBool = true;
			settingsBtn.removeEventListener(MouseEvent.CLICK, settingsHandler);
			minimizeButton.removeEventListener(MouseEvent.CLICK, minimizeHandler);
			maximizeButton.removeEventListener(MouseEvent.CLICK, maximizeHandler);
			closeButton.removeEventListener(MouseEvent.CLICK, closeHandler);
			removeEventListener(MouseEvent.MOUSE_DOWN, bringToTop);
			titleBar.removeEventListener(MouseEvent.MOUSE_DOWN,titleBar_mouseDownHandler);
			titleBar.removeEventListener(MouseEvent.MOUSE_OUT,titleBar_mouseOutHandler);
			titleBar.removeEventListener(MouseEvent.MOUSE_UP,titleBar_mouseUpHandler);
			titleBar.removeEventListener(MouseEvent.DOUBLE_CLICK,titleBar_doubleClickHandler);
			
			titleBar.removeChild(closeButton as DisplayObject);
			titleBar.removeChild(maximizeButton as DisplayObject);			
			titleBar.removeChild(minimizeButton as DisplayObject);
			titleBar.removeChild(settingsBtn as DisplayObject);
			
			minimizeButton.styleName =
				maximizeButton.styleName = 
				closeButton.styleName = 
				settingsBtn.styleName = "";
			
			if (this.popUpModalContainer != null && this.popUpModalContainer.numChildren > 0)
			{
				this.removePopUp();
			}
			inlinePopUpRender = null;
			
			closeButton = null;
			maximizeButton = null;
			minimizeButton = null;
			settingsBtn = null;
			
			this.removeAllChildren();
		}
		override protected function createChildren():void
		{
			super.createChildren();
			
			settingsBtn = new Button();
			settingsBtn.y = 6;
			settingsBtn.width = 18;
			settingsBtn.height = 18;
			settingsBtn.setStyle("icon", iconSettings);
			settingsBtn.addEventListener(MouseEvent.CLICK, settingsHandler);
			
			minimizeButton = new Button();
			minimizeButton.y = 6;
			minimizeButton.width = 18;
			minimizeButton.height = 18;
			minimizeButton.setStyle("icon", iconMinimize);
			minimizeButton.addEventListener(MouseEvent.CLICK, minimizeHandler);
			
			maximizeButton = new Button();
			maximizeButton.y = 6;
			maximizeButton.width = 18;
			maximizeButton.height = 18;
			maximizeButton.setStyle("icon", iconMaximize);
			maximizeButton.addEventListener(MouseEvent.CLICK, maximizeHandler);

			closeButton = new Button();
			closeButton.y = 6;
			closeButton.width = 18;
			closeButton.height = 18;
			closeButton.setStyle("icon", iconClose);
			closeButton.addEventListener(MouseEvent.CLICK, closeHandler);
			
			titleBar.addChild(closeButton);
			titleBar.addChild(maximizeButton);			
			titleBar.addChild(minimizeButton);
			titleBar.addChild(settingsBtn);
			
			settingsBtn.toolTip = 'Settings';
			minimizeButton.toolTip = 'Minimize Panel';
			maximizeButton.toolTip = 'Maximize Panel';
			closeButton.toolTip = 'Close Panel';
			
			var buttonsBarStyleName:String = getStyle("buttonsBarStyleName") as String;
			
			if(buttonsBarStyleName) {
				minimizeButton.styleName =
				maximizeButton.styleName = 
				closeButton.styleName = 
				settingsBtn.styleName = buttonsBarStyleName;
			}
			
			addEventListener(MouseEvent.MOUSE_DOWN, bringToTop);
			
			/*if(parent != null) {
				parent.addEventListener(ResizeEvent.RESIZE, parentResizeHandler);
			}
			*/
			originalCornerRadius = getStyle("cornerRadius");
			//detect a custom titleBar handler
			
			titleBar.addEventListener(MouseEvent.MOUSE_DOWN,titleBar_mouseDownHandler);
			titleBar.addEventListener(MouseEvent.MOUSE_OUT,titleBar_mouseOutHandler);
			titleBar.addEventListener(MouseEvent.MOUSE_UP,titleBar_mouseUpHandler);
			titleBar.addEventListener(MouseEvent.DOUBLE_CLICK,titleBar_doubleClickHandler);

			titleBar.doubleClickEnabled = true;
		}
		/**
		 * Getter for accessing the title bar window.
		 *  
		 * @return 
		 * 
		 */		
		public function get TitleBar() :UIComponent {
			
			return titleBar;
		}
		
		private var middleOverLay:UIComponent;
		
		public function addMiddleOverlay(child:DisplayObject):DisplayObject {
			if(!middleOverLay) {
				middleOverLay = new inlinePopUpRender ();
				//inSidePop
				var modalStyleName:Object = getStyle("modalStyleName");
				middleOverLay.styleName = modalStyleName;
				rawChildren.addChild(middleOverLay);
			}
			return middleOverLay.addChild(child);
		}
		public function removeMiddleOverlay(child:DisplayObject):DisplayObject {
			return rawChildren.removeChild(child);
		}
		
		private function createInLinePopUp():void
		{
			//add a pop-inline handler container.
			if(!inSidePop) {
				inSidePop = new inlinePopUpRender ();
				//inSidePop
				var modalStyleName:Object = getStyle("modalStyleName");
				inSidePop.styleName = modalStyleName;
				inSidePop.visible = false;
				rawChildren.addChild(inSidePop);
				modalActive = false;
			}
		}
		override protected function commitProperties():void
    	{
    		super.commitProperties();
    		
    		if(_buttonsBarVisibleChanged) {
    			maximizeButton.setVisible(_showiconsbar,true);
    			minimizeButton.setVisible(_showiconsbar,true);
    			settingsBtn.setVisible(_showiconsbar,true);
    			closeButton.setVisible(_showiconsbar,true);
				_buttonsBarVisibleChanged = false;
    		}
			if (_buttonsBarEnabledChanged) {
				_buttonsBarEnabledChanged = false;
				maximizeButton.enabled = settingsBtn.enabled = closeButton.enabled = _enabledBBar;
			}
			if (_maximizedChange)
			{
				
				if(!_maximized) {
					if(maximizeButton) {
						maximizeButton.setStyle("icon", iconMaximize);
					}
					//restore the window from the maximized state.
					dispatchEvent(new Event(RESTORE));		
				} else {
					if(maximizeButton) {
						maximizeButton.setStyle("icon", iconRestore);
					}
					dispatchEvent(new Event(MAXIMIZE));
				}
				_maximizedChange = false;
			}
			if (_minimizedChange ) {
				//restore the window from the minimized state.
				if (!_minimized) {
					dispatchEvent(new Event(RESTORE));
				} else {
					dispatchEvent(new Event(MINIMIZE));
				}
				_minimizedChange = false;
			}
			
			if(_childsvisibleschanged) {
				_childsvisibleschanged = false;
				var t:int = this.numChildren;
				while(t>0) {
					this.getChildAt(t-1).visible = _childsvisible;
					t--;
				}
			}
			
    	}
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if ( destroyBool )
				return;
			maximizeButton.setVisible(_showiconsbar,true);
    		minimizeButton.setVisible(false,true);
    		settingsBtn.setVisible(_showiconsbar,true);
    		closeButton.setVisible(_showiconsbar,true);
			
			closeButton.move(unscaledWidth - 24,4);
			maximizeButton.move(closeButton.x - 18,4);
			minimizeButton.move(maximizeButton.x - 18,4);
			settingsBtn.move(maximizeButton.x - 18,4);
			
			statusTextField.move(settingsBtn.x - statusTextField.width,4);
			
			if(inSidePop) {
				inSidePop.move(0,titleBar.height + titleBar.y + 2);
				//1@ inSidePop.y = 0;
				inSidePop.setActualSize(width, height - inSidePop.y);
				//1@ inSidePop.height = height;
			}
			if (middleOverLay) {
				middleOverLay.move(0,titleBar.height + titleBar.y + 2);
				//1@ inSidePop.y = 0;
				middleOverLay.setActualSize(width, height - middleOverLay.y);
			}
		}
		/**
		 * addPopUp , add an in-situ popup to this window.
		 * Usefull if you need to create a modal window that block the user interaction
		 * inside the Window Panel container but not block the main application.
		 * you can also especefy a <code>modal = false</code> param to non block the user interaction
		 * inside this object. but is not the main idea.
		 * 
		 * @param child DisplayObject that will be added to the display list.
		 * @param modal Boolean this will change the mode of the pop-up background interaction.
		 * 
		 **/
		public function addPopUp(child:DisplayObject, modal:Boolean=true):DisplayObject {
			
			createInLinePopUp();
			
			if(modal){
				inSidePop.setStyle('backgroundColor', inSidePop.getStyle('backgroundColor'));
				inSidePop.setStyle('backgroundAlpha', inSidePop.getStyle('backgroundAlpha'));
			}
			else {
				inSidePop.setStyle('backgroundColor',undefined);
				inSidePop.setStyle('backgroundAlpha',0);
			}
			modalActive = true;
			return inSidePop.addChild(child);
		}
		/**
		 * Hide the in-line popUp container window.
		 * this method not remove any componentes inside it.
		 * 
		 **/
		public function hidePopUp():void {
			modalActive = false;
		}
		/**
		 * Show the in-line popUp container window.
		 **/
		public function showPopUp():void {
			modalActive = true;
		}
		/**
		 * Remove a IDisplayObject from the pop up window if you add a lot of this.
		 * If you pass <code>ui=null</code> as parameter you will remove all components.
		 * If you pass <code>ui=UIComponente_instance</code> the pop-up inline will remove only this component.
		 * If the removed componente is the lates compontent no the display list the pop-modal will be hidded.
		 * 
		 * @param ui DisplayObject the component you wanto to remove from the display list in the pop-up.
		 * @param autoHidePopUp Boolean if this parameter is true the component automatically hide the pop-modal container
		 * if after removing the poped-up component.
		 * 
		 **/
		public function removePopUp(ui:DisplayObject = null, autoHidePopUp:Boolean=false):void {
			if(ui){
				VBox(inSidePop).removeChild(ui);
				if(VBox(inSidePop).getChildren().length<1 && autoHidePopUp) {
					hidePopUp();
				}
			}else {
				VBox(inSidePop).removeAllChildren();
				inSidePop = null;
				if(autoHidePopUp) hidePopUp();
			}
		}
		/**
		 * Query the component to know if they has more pop-ups in the child list.
		 * So you can safelly remote the pop-insitu object.
		 * 
		 * @return Boolean
		 **/
		public function hasPopUpChilds():Boolean {
			if(!inSidePop) return false;
			return VBox(inSidePop).getChildren().length>0;
		}
		/**
		 * Change the mode that you display the in-line pop-up.
		 * Posible values are true | false.
		 * this allow the user to interact  with the bottom components.
		 **/
		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
		[Bindable]
		public function set popUpModal(ismodal:Boolean):void
		{
			_pop_modal = ismodal;
			if(inSidePop.getStyle('backgroundAlpha')){
				__storedAlpha = inSidePop.getStyle('backgroundAlpha');
				__storedColor = inSidePop.getStyle('backgroundColor');
			}
			if(_pop_modal){
				inSidePop.setStyle('backgroundColor',__storedColor);
				inSidePop.setStyle('backgroundAlpha',__storedAlpha);
			}
			else {
				inSidePop.setStyle('backgroundColor',null);
				inSidePop.setStyle('backgroundAlpha',0);
			}
		}
		public function get popUpModal():Boolean
		{
			return _pop_modal;
		}
		/**
		 * Change the modal state in order to show it or hide it.
		 * Posible values are true | false.
		 * this allow tho bind to other components.
		 *
		 **/
		[Bindable]
		public function set modalActive(value:Boolean):void
		{
			_modal_active = value;
			inSidePop.visible = _modal_active;
			if(_modal_active) {
				dispatchEvent(new Event(WindowPanel.SHOW_POPUP));
			}
			else {
				dispatchEvent(new Event(WindowPanel.HIDE_POPUP));
			}
		}
		public function get modalActive():Boolean
		{
			return _modal_active;
		}
		/**
		 * This method allow you to change the pop-up container in order to use a custom component.
		 * 
		 * @todo feature not tested
		 **/
		[Bindable]
		public function set popUpModalContainer(container:UIComponent):void
		{
			inSidePop = container;
		}
		public function get popUpModalContainer():UIComponent
		{
			return inSidePop;
		}
		
		
		
		private var _buttonsBarVisibleChanged:Boolean = false;
		private var _showiconsbar:Boolean = true;
		
		[Bindable]
		public function set buttonsBarVisible(value:Boolean):void
		{
			_showiconsbar = value;
			_buttonsBarVisibleChanged = true;
			invalidateProperties();
		}
		public function get buttonsBarVisible():Boolean
		{
			return _showiconsbar;
		}
		
		
		private var _buttonsBarEnabledChanged:Boolean = false;
		private var _enabledBBar:Boolean = true;
		
		
		/**
		 * Deshabilita/habilita los botones de arriba 
		 * @param value Boolean
		 * 
		 */
		[Bindable]

		public function set buttonsBarEnabled(value:Boolean):void
		{
			_enabledBBar = value;
			_buttonsBarEnabledChanged = true;
			invalidateProperties();
		}
		public function get buttonsBarEnabled():Boolean
		{
			return _enabledBBar;
		}

		[Bindable]
		public function set resizable(value:Boolean):void
		{
			_resizable = value;
			//grip.visible = _resizable;
		}
		public function get resizable():Boolean
		{
			return _resizable;
		}


		public function bringTop():void {
			if(parent != null) {
				parent.setChildIndex(this,parent.numChildren - 1);
			} 
		}
		protected function bringToTop(event:MouseEvent=null):void
		{
			if(!autoBringToTop) return;
			if(parent != null) {
				parent.setChildIndex(this,parent.numChildren - 1);
			} 
		}
		
		protected function parentResizeHandler(event:Event):void
		{
			if(!resizable) return;
			if (parent==null) return;
			if (maximized)
			{
				setActualSize(parent.width,parent.height);				
			}
			if (!minimized && !maximized)
			{
				if (x > parent.width - 50) x = parent.width - 100;
				if (y > parent.height - 50) y = parent.height - 100;
			}
		}

		protected function minimizeHandler(event:Event):void
		{
			//minimized = true;
			if(!minimized){
				dispatchEvent(new Event(WindowPanel.MINIMIZE_CLICK));
			} else {
				this.dispatchEvent(new Event(RESTORE));
			}
		}
		
		private var _childsvisibleschanged:Boolean = false;
		private var _childsvisible:Boolean = true;
		[Bindable]
		/**
		 * Show / hide the childrens inside the panel window
		 * this is for faster render when contain effects. 
		 * @param value
		 * 
		 */		
		public function set childsVisible (value:Boolean) :void {
			_childsvisible = value;
			_childsvisibleschanged = true;
			
			invalidateProperties();
		}
		
		public function get childsVisible():Boolean {
			return _childsvisible;
		}
		
		protected function maximizeHandler(event:Event):void
		{
			if(!maximized) {
				this.dispatchEvent(new Event(MAXIMIZE_CLICK));
			} else {
				this.dispatchEvent(new Event(RESTORE));
			}
		}
		
		private var _minimizedChange:Boolean = false;
		private var _minimized:Boolean = false;
		
		[Bindable]
		public function set minimized (value:Boolean):void {
			_minimized = value;
			_minimizedChange = true;
			invalidateProperties();
		}
		public function get minimized ():Boolean {
			return _minimized;
		}
		
		private var _maximizedChange:Boolean = false;
		private var _maximized:Boolean = false;
		
		[Bindable]
		public function set maximized (value:Boolean):void {
			_maximized = value;
			_maximizedChange = true;
			
			invalidateProperties();
		}
		public function get maximized ():Boolean {
			return _maximized;
		}
		
		protected function doMaximize(w:Number, h:Number):void {
			this.width = w;
			this.height = h;
			this.parent.addEventListener(ResizeEvent.RESIZE,handleResizeParent);
		}
		
		public function handleResizeParent(event:Event):void {
			this.width = event.currentTarget.width - event.currentTarget.getStyle('paddingLeft');
			this.height = event.currentTarget.height - event.currentTarget.getStyle('paddingTop');
		}
		protected function doRestore():void {
			this.x = this.originalX;
			this.y = this.originalY;
			this.width = originalWidth;
			this.height = originalHeight;
			this.parent.removeEventListener(ResizeEvent.RESIZE,handleResizeParent);
		}
		
		private function settingsHandler(event:Event):void {
			dispatchEvent(new Event(WindowPanel.SETTINGS_OPEN_EVENT));
		}
		
		protected function closeHandler(event:Event):void
		{
			var ev:CloseEvent = new CloseEvent(CloseEvent.CLOSE); 
			dispatchEvent(ev);
			ev = null;
		}

		/**
		 * hack for stop draging the window if you press the buttons bar.
		 * 
		 **/
		private function titleBar_mouseDownHandler(event:MouseEvent):void {
			if(event.target.className == 'Button' || maximized) {
				stopDragging();
			}
			if(event.target.className != 'Button'){
				if(minimized) {
					//si esta minimizado tiro el evento restore
					this.dispatchEvent(new Event(WindowPanel.RESTORE));			
					return;	
				}
				if(isPopUp) {
					this.alpha = 0.4;
				}
				this.dispatchEvent(new Event(ON_TITLE_BAR_PRESS));
			}
		}
		private function titleBar_mouseOutHandler(event:MouseEvent):void
		{
			if(maximized && isPopUp){ alpha = 1;} 
		}
		private function titleBar_mouseUpHandler(event:MouseEvent):void {
			this.alpha = 1;
			this.dispatchEvent(new Event(ON_TITLE_BAR_RELEASE));
		}
		private function titleBar_doubleClickHandler(event:MouseEvent):void {
			if(parent != null && (MouseEvent(event).target.className != 'Button')) {
				maximizeHandler(event);
			}
		}
	}
}